package internal

import (
	"regexp"
	"strings"

	jsonIter "github.com/json-iterator/go"

	"github.com/coocood/freecache"
)

func GetHost(url string, index int32, hostAndUrls []string) string {
	host := ""
	if url != "" {
		temp := "://"
		startHost := strings.Index(url, temp)
		var endHost int
		if startHost != -1 {
			startHost += len(temp)
			endHost = strings.LastIndex(url, "/")
			if endHost > startHost {
				host = url[startHost:endHost]
			} else {
				host = url[startHost:]
			}
			endHost = strings.Index(host, ":")
			if endHost != -1 {
				host = host[0:endHost]
			}
		}
	}
	if "" == host {
		host = GetHostFromIndex(index, hostAndUrls)
	}
	return host
}

func GetHostFromIndex(index int32, hostAndUrls []string) string {
	host := ""
	// 由于传过来的 index 是以 1 开始的
	index--
	length := int32(len(hostAndUrls))
	if 0 <= index && index < length {
		host = hostAndUrls[index]
	}
	return host
}

func getTableAndOpFromDatabaseSQL(sql string, cache *freecache.Cache) (string, string) {
	// 先从缓存里找结果
	CacheKeyURLEntityCache := JoinStrings([]string{CacheKeySQLTableOperateCacheSuffix, sql}, "")
	entityValue := getCacheSQLTableOperate(CacheKeyURLEntityCache, cache)
	if nil != entityValue {
		return entityValue.Table, entityValue.Operate
	}

	// 没有找到重新走正则
	entity := &SQLEntity{}

	regexList := make([]map[string]string, 16)
	regexList[0] = map[string]string{
		"operate": "select",
		"regex":   "(?i)^\\s*select.*?\\sfrom[\\s\\[]+([^\\]\\s,)(;]*).*",
		"func":    "DefaultStatementFactory",
	}
	regexList[1] = map[string]string{
		"operate": "select",
		// "regex":  "\\s*SELECT.*?\\sFROM\\s*\\(\\s*(SELECT.*)",
		"regex": "(?i)^\\s*SELECT.*?\\sFROM\\s*\\(\\s*(SELECT[\\s\\S]*)",
		"func":  "InnerSelectStatementFactory",
	}
	regexList[2] = map[string]string{
		"operate": "show",
		"regex":   "(?i)^\\s*show create table\\s+([^\\s,;]*).*",
		"func":    "DefaultStatementFactory",
	}
	regexList[3] = map[string]string{
		"operate": "show",
		"regex":   "(?i)^\\s*show\\s+(.*)$",
		"func":    "DefaultStatementFactory",
	}
	regexList[4] = map[string]string{
		"operate": "insert",
		"regex":   "(?i)^\\s*insert(?:\\s+ignore)?\\s+into\\s+([^\\s(,;]*).*",
		"func":    "DefaultStatementFactory",
	}
	regexList[5] = map[string]string{
		"operate": "update",
		"regex":   "(?i)^\\s*update\\s+([^\\s,;]*).*",
		"func":    "DefaultStatementFactory",
	}
	regexList[6] = map[string]string{
		"operate": "delete",
		"regex":   "(?i)^\\s*delete\\s+from\\s+([^\\s,(;]*).*",
		"func":    "DefaultStatementFactory",
	}
	regexList[7] = map[string]string{
		"operate": "create",
		"regex":   "(?i)^\\s*create\\s+procedure.*", // type=Procedure
		"func":    "DDLStatementFactory",
		"table":   "Procedure",
	}
	regexList[8] = map[string]string{
		"operate": "select",
		"regex":   "(?i).*select\\s+([^\\s,]*).*",
		"func":    "SelectVariableStatementFactory",
	}
	regexList[9] = map[string]string{
		"operate": "drop",
		"regex":   "^(?i)\\s*drop\\s+procedure.*",
		"func":    "DDLStatementFactory",
		"table":   "Procedure",
	}
	regexList[10] = map[string]string{
		"operate": "create",
		"regex":   "^(?i)\\s*create\\s+table.*", // Table
		"func":    "DDLStatementFactory",
		"table":   "Table",
	}
	regexList[11] = map[string]string{
		"operate": "drop",
		"regex":   "^(?i)\\s*drop\\s+table.*", // Table
		"func":    "DDLStatementFactory",
		"table":   "Table",
	}
	regexList[12] = map[string]string{
		"operate": "alter",
		"regex":   "^(?i)\\s*alter\\s+([^\\s]*).*",
		"func":    "DefaultStatementFactory",
	}
	regexList[13] = map[string]string{
		"operate": "call",
		"regex":   "(?i).*call\\s+([^\\s(,]*).*",
		"func":    "DefaultStatementFactory",
	}
	regexList[14] = map[string]string{
		"operate": "exec",
		"regex":   "(?i).*(?:exec|execute)\\s+([^\\s(,]*).*",
		"func":    "DefaultStatementFactory",
	}
	regexList[15] = map[string]string{
		"operate": "set",
		"regex":   "(?i)^\\s*set\\s+(.*)\\s*(as|=).*",
		"func":    "DefaultStatementFactory",
	}
	// 统计所有已知的操作
	knownOperations := make(map[string]string)
	for _, value := range regexList {
		for key := range value {
			knownOperations[key] = key
		}
	}

	regex := "(?i)\\s*/\\*\\s*nrhint\\s*:\\s*([^\\*]*)\\s*\\*/\\s*([^\\s]*).*"
	reg := regexp.MustCompile(regex)
	result := reg.FindStringSubmatch(sql)
	if len(result) >= 3 {
		result[2] = strings.Trim(result[2], " ")
		if _, ok := knownOperations[result[2]]; !ok {
			result[2] = ""
		}
		entity = &SQLEntity{Table: strings.Trim(result[1], " "), Operate: result[2]}
	} else {
		sqlRegxp := regexp.MustCompile(`/\*.*?\*/`)
		newSQL := strings.Replace(sql, sqlRegxp.FindString(sql), "", 1)
		newSQL = strings.ReplaceAll(newSQL, "\n", " ")
		for _, value := range regexList {
			switch value["func"] {
			case "DefaultStatementFactory":
				entity = defaultStatementFactory(value, newSQL)
			case "DDLStatementFactory":
				entity = ddlStatementFactory(value, newSQL)
			case "SelectVariableStatementFactory":
				entity = selectVariableStatementFactory(value, newSQL)
			case "InnerSelectStatementFactory":
				innerSelectStatementFactory(value, newSQL, regexList[0]["regex"])
			}
			if entity.Table != "" {
				break
			}
		}
	}
	json := jsonIter.ConfigCompatibleWithStandardLibrary
	entityByte, _ := json.Marshal(entity)
	_ = cache.Set([]byte(CacheKeyURLEntityCache), entityByte, 3600*24)
	return entity.Table, entity.Operate
}

func innerSelectStatementFactory(value map[string]string, sql string, defaultRegex string) *SQLEntity {
	var res string
	for {
		var res2 string
		regex := regexp.MustCompile(value["regex"])
		result := regex.FindStringSubmatch(sql)
		if len(result) >= 2 {
			res2 = result[1]
		} else if result == nil {
			break
		}
		res = res2
		sql = res2
	}
	value["regex"] = defaultRegex
	if res != "" {
		return defaultStatementFactory(value, res)
	}
	return defaultStatementFactory(value, sql)
}

func selectVariableStatementFactory(value map[string]string, sql string) *SQLEntity {
	entity := &SQLEntity{}
	reg := regexp.MustCompile(value["regex"])
	if reg.MatchString(sql) {
		reg2 := regexp.MustCompile(`(?i)\s+from\s+`)
		if reg2.MatchString(sql) {
			entity.Operate = value["operate"]
			entity.Table = "INNER_SELECT"
		} else {
			entity.Operate = value["operate"]
			entity.Table = "VARIABLE"
		}
	}
	return entity
}

func ddlStatementFactory(value map[string]string, sql string) *SQLEntity {
	entity := defaultStatementFactory(value, sql)
	if entity.Table == "" {
		reg := regexp.MustCompile(value["regex"])
		if reg.MatchString(sql) {
			entity.Operate = value["operate"]
			entity.Table = value["table"]
		}
	}
	return entity
}

func defaultStatementFactory(value map[string]string, sql string) *SQLEntity {
	entity := &SQLEntity{}
	reg := regexp.MustCompile(value["regex"])
	result := reg.FindStringSubmatch(sql)
	if len(result) >= 2 {
		entity.Operate = value["operate"]
		entity.Table = strings.Trim(result[1], " ")
		entity.Table = unquoteDatabaseName(entity.Table)
	}
	return entity
}

func unquoteDatabaseName(table string) string {
	index := strings.IndexByte(table, 46)
	if index > 0 {
		return unquote(table[0:index]) + "." + unquote(table[index+1:])
	}
	return unquote(table)
}

func unquote(table string) string {
	if table == "" || len(table) < 2 {
		return table
	}
	first := table[0:1]
	last := table[len(table)-1:]
	if first != last || first != "\\\"" && first != "\\'" && first != "`" {
		return table
	}
	return table[1 : len(table)-1]
}

func getCacheSQLTableOperate(cacheKey string, cache *freecache.Cache) *SQLEntity {
	entity := &SQLEntity{}
	entityByte, err := cache.Get([]byte(cacheKey))
	if nil == err && nil != entityByte {
		json := jsonIter.ConfigCompatibleWithStandardLibrary
		err = json.Unmarshal(entityByte, entity)
		if nil == err {
			return entity
		}
	}
	return nil
}
